use chrono::Local;
use sqlite_wasm_rs::sqlite3_stmt;
use crate::db::dao::base_dao::Adder;
use crate::db::db::{Db, DbParamType};
use crate::db::pojo::pojo::ImLabel;
use crate::db::util::{db_get_enum, db_get_int64, db_get_string, db_get_time};

const SELECT_COLUMNS: &'static str = "id, serverId, currentUserId, name, status, createTime, updateTime";

pub fn label_inserts(db: Db, labels: &mut Vec<&mut ImLabel>) {
    if labels.is_empty() {
        return;
    }

    let sql = c"insert into im_label(serverId, currentUserId, name, status, createTime, updateTime) values(?, ?, ?, ?, ?, ?)";

    let mut params = vec![];
    for label in labels.iter() {
        let mut param = vec![];
        param.push(DbParamType::OptionStr(label.server_id.as_ref()));
        param.push(DbParamType::Str(&*label.current_user_id));
        param.push(DbParamType::Str(&*label.name));
        param.push(DbParamType::Byte(label.status.clone() as i8));
        param.push(DbParamType::DateTime2(&label.create_time));
        param.push(DbParamType::DateTime2(&label.update_time));
        params.push(param);
    }

    log::info!("db label params {:?}", params);
    let ids = db.inserts("label inserts", sql, params);
}

pub fn label_updates(db: Db, labels: &mut Vec<&mut ImLabel>) {
    if labels.is_empty() {
        return;
    }
    let sql = "update im_label set serverId = ?, status =?, updateTime = ? where id = ?";
    let mut params = vec![];
    for label in labels.iter() {
        let mut param = vec![];
        param.push(DbParamType::OptionStr(label.server_id.as_ref()));
        param.push(DbParamType::Byte(label.status.clone() as i8));
        param.push(DbParamType::DateTime(Local::now()));
        param.push(DbParamType::Uint(label.id.unwrap()));
        params.push(param);
    }
    log::info!("db label update params: {:?}", params);
    db.batch_exec("label updates", sql.to_string(), params);
}

pub fn query_labels_by_names(db: Db, current_user_id: &str, names: Vec<&str>) -> Vec<ImLabel> {
    let sql_where = names.iter().map(|_name| "?").collect::<Vec<&str>>().join(",");
    let sql = format!("select {} from im_label where currentUserId=? and name in ({})", SELECT_COLUMNS, sql_where);
    let mut params = vec![];
    params.push(DbParamType::Str(current_user_id));
    for name in names.into_iter() {
        params.push(DbParamType::Str(name));
    }
    db.query2("label query", &sql, params, Box::new(label_wrap))
}

pub fn query_label_by_name(db: Db, current_user_id: String, name: String) -> Option<ImLabel> {
    let sql = format!("select {} from im_label where currentUserId=? and name = ?", SELECT_COLUMNS);
    let mut params = vec![];
    params.push(DbParamType::String(current_user_id));
    params.push(DbParamType::String(name));

    db.query_one("label query1", sql.to_string(), params, Box::new(label_wrap))
}

pub fn query_label_by_server_id(db: Db, current_user_id: String, name: String) -> Option<ImLabel> {
    let sql = format!("select {} from im_label where currentUserId=? and name = ?", SELECT_COLUMNS);
    let mut params = vec![];
    params.push(DbParamType::String(current_user_id));
    params.push(DbParamType::String(name));

    db.query_one("label query2", sql.to_string(), params, Box::new(label_wrap))
}

pub fn label_total(db: Db)-> usize {
    let size = db.count("label total", c"select count(*) from im_label", Vec::new());
    log::info!("db label count: {}", size);
    size
}


fn label_wrap(stmt: *mut sqlite3_stmt) -> ImLabel {
    unsafe {
        let mut adder = Adder::new();
        let id = db_get_int64(stmt, adder.add());
        let server_id = db_get_string(stmt, adder.add());
        let current_user_id = db_get_string(stmt, adder.add()).unwrap();
        let name = db_get_string(stmt, adder.add()).unwrap();
        let status = db_get_enum(stmt, adder.add());
        let create_time = db_get_time(stmt, adder.add());
        let update_time = db_get_time(stmt, adder.add());

        ImLabel {
            id: Some(id),
            current_user_id,
            server_id,
            name,
            status,
            create_time,
            update_time,
        }
    }
}